Примеры обратного проксирования VLESS
В этой статье показано, как использовать возможность обратного проксирования VLESS в Xray, чтобы через публичный сервер возвращать трафик в удаленную внутреннюю сеть или даже продолжать выход во внешний интернет через домашний широкополосный канал. Ниже рассмотрены три распространенных сценария:
Проброс входа: удаленный проброс порта, то есть сопоставление публичного входного порта с Web-сервисом в удаленной внутренней сети;Удаленно домой: удаленный роуминг по внутренней сети, когда пользователь проходит через публичный сервер и затем продолжает доступ к ресурсам домашней сети;Выход через домашний канал: пользователь проходит через публичный сервер, отправляет выбранный трафик обратно на домашнее устройство, а затем выходит во внешний интернет через домашний широкополосный канал.
Проброс Входа
Удаленный проброс порта, то есть сопоставление публичного входного порта с Web-сервисом в удаленной внутренней сети.
Как Это Работает
В этой модели есть три роли:
- Пользователь: обращается к публичной точке входа;
- Публичный сервер: принимает трафик и передает его в туннель обратного прокси;
- Внутреннее устройство: само устанавливает соединение с публичным сервером и принимает запросы через обратный туннель.
Проще говоря:
- Внутреннее устройство сначала само подключается к публичному серверу.
- Публичный сервер удерживает этот обратный туннель.
- Пользователь обращается к входу
443на публичном сервере. - Публичный сервер отправляет запрос обратно во внутреннее устройство через обратный туннель.
- Внутреннее устройство переписывает цель на реальный Web-сервис.
Идея Конфигурации
В обратном проксировании VLESS есть два ключевых момента:
- На публичной стороне для одного из клиентов VLESS объявляется
reverse.tag, и тогда он будет выглядеть как маршрутизируемый outbound; - На внутренней стороне для одного из outbound-соединений VLESS объявляется
reverse.tag, и тогда оно будет само устанавливать обратное соединение и локально проявляться как inbound, способный принимать трафик.
Значения reverse.tag на обеих сторонах не обязаны совпадать. Это лишь локальные идентификаторы в своих конфигурациях. Реальное соответствие задается самой обратной связью.
Конфигурация Публичного Сервера
Пример ниже делает две вещи:
- Поднимает inbound VLESS на порту
8443, где одинclientсодержитreverseи поэтому специально используется для установления обратных соединений с внутренних устройств; - Поднимает inbound
tunnelна порту443, который снаружи используется как вход Web-сервиса, а весь пришедший туда трафик перенаправляется в туннель обратного прокси.
Также обратите внимание, что outbound freedom нужно оставить как заглушку. Иначе, если outbounds окажется пустым, reverse-out будет считаться outbound по умолчанию, и трафик, не совпавший ни с одним правилом маршрутизации, может по ошибке попасть в туннель обратного прокси.
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 8443,
"protocol": "vless",
"settings": {
"decryption": "mlkem768x25519plus.native.600s.aCF82eKiK6g0DIbv0_nsjbHC4RyKCc9NRjl-X9lyi0k",
"clients": [
{
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-out"
}
}
// ... остальные обычные client
]
}
},
{
"listen": "0.0.0.0",
"port": 443,
"protocol": "tunnel",
"tag": "portal"
}
],
"routing": {
"rules": [
{
"inboundTag": ["portal"],
"outboundTag": "reverse-out"
}
]
},
"outbounds": [
{
"protocol": "freedom"
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Конфигурация Внутреннего Устройства
Задача внутреннего устройства состоит в том, чтобы само инициировать исходящее соединение и создать обратный туннель. Здесь дополнительно задается маршрут, чтобы трафик, приходящий через reverse-in, явно отправлялся в указанный outbound freedom, а не целиком зависел от outbound по умолчанию, потому что на практике Xray на внутренней стороне часто еще обслуживает обычный прямой прокси.
В примере сохранены два outbound freedom:
- Один обычный
freedom, который используется как outbound прямого подключения по умолчанию;
(если вам также нужен прямой прокси, остальные части такой конфигурации здесь опущены) - Один
freedomсtag, специально предназначенный для приема трафика, пришедшего через inbound обратного прокси.
Предположим, что ваш внутренний Web-сервис слушает на 192.168.1.123:8888:
- На outbound нужно переписать целевой адрес на этот внутренний адрес;
- Поскольку в Xray действует политика безопасности по умолчанию, целевой порт нужно явно разрешить в
finalRules.
{
// Остальная конфигурация, связанная с прямым прокси, опущена...
"routing": {
"rules": [
{
"inboundTag": ["reverse-in"],
"outboundTag": "reverse-direct"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "reverse-direct",
"settings": {
"redirect": "192.168.1.123:8888",
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.123",
"port": "8888"
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-in"
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Важно понимать следующее:
- На публичной стороне
reverse.tagпроявляется как outbound; - На внутренней стороне
reverse.tagпроявляется как inbound; - Они не обязаны называться одинаково, главное, чтобы обе стороны соответствовали одной и той же обратной связи
ac04551d...; - Если вы хотите тоньше управлять трафиком, приходящим через обратный прокси на внутренней стороне, можно, как в примере выше, явно указать в
routing, через какойfreedomoutbound он должен идти. - На внутренней стороне также поддерживается
sniffing, а если вfreedomнастроитьproxyProtocol, ваш Web-сервер сможет видеть реальный IP посетителя. Здесь эту тему не раскрываем.
Поток Запроса
Смысл такого сценария вполне ясен: для пользователя это выглядит как "доступ к Web-сервису на публичном сервере", но фактически запросы обрабатывает Web-сервис на устройстве в удаленной внутренней сети.
Несколько Каналов и Резервирование
Одно внутреннее устройство может устанавливать несколько обратных соединений, например через разные сети, разные исходящие каналы или разные адреса входа на публичном сервере. Если публичная сторона рассматривает все эти соединения как одну и ту же цель обратного прокси, получается резервирование каналов.
Преимущества такого подхода:
- Если один канал временно недоступен, трафик может идти по другим;
- На публичной стороне не нужно проектировать отдельную схему маршрутизации для каждого канала;
- Для сценариев проброса во внутреннюю сеть так удобнее организовывать резервирование.
Рекомендации По Безопасности
- На публичном сервере обязательно должен оставаться явный outbound по умолчанию. В зависимости от ваших задач это может быть
freedom,blackholeили что-то похожее, чтобы трафик, не совпавший с маршрутами, случайно не попадал в обратный прокси; - Пример конфигурации в первую очередь объясняет принцип. В реальной публичной сети обычно также требуется более полноценная транспортная схема и маскировка.
Удаленно Домой
Удаленный роуминг по внутренней сети, когда пользователь проходит через публичный сервер и возвращается в домашнюю сеть, чтобы продолжать доступ к ресурсам.
Описание Сценария
Здесь речь не о том, чтобы открыть какой-то публичный порт для внешнего доступа. Вместо этого пользователь сначала подключается к публичному Xray-серверу, а затем с помощью уже установленного обратного туннеля его трафик отправляется обратно на домашнее внутреннее устройство для дальнейшей обработки.
Этот вариант ближе к следующим сценариям:
- Доступ к ресурсам домашней локальной сети во время поездок;
- Переход через публичный сервер с последующим доступом к NAS, панели роутера или другим внутренним сервисам.
Идея Конфигурации
По сравнению с первой частью, главное отличие здесь не в самой обратной связи, а в цели маршрутизации на публичной стороне:
- В первой части используется
inboundTag -> reverse-out, чтобы сопоставить определенный входной порт с внутренней сетью; - В этой части используется
user -> reverse-out, чтобы передать проксируемый трафик конкретного пользователя внутреннему устройству для дальнейшей обработки.
Иными словами, здесь публичный сервер больше похож на транзитный узел. Пользователь не "обращается напрямую к сервису, проброшенному через публичный порт", а "сначала подключается к входу Xray на публичном сервере, а затем продолжает путь через домашнее устройство".
Конфигурация Публичного Сервера
В этом примере:
- Первый UUID по-прежнему используется домашним устройством для установления обратного соединения;
- Второй UUID используется внешним пользователем для подключения к публичному серверу;
- Маршрутизация по
emailотправляет трафик этого пользователя вreverse-out.
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 8443,
"protocol": "vless",
"settings": {
"decryption": "mlkem768x25519plus.native.600s.aCF82eKiK6g0DIbv0_nsjbHC4RyKCc9NRjl-X9lyi0k",
"clients": [
{
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-out"
}
},
{
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision",
"email": "roam@example.com"
}
]
}
}
],
"routing": {
"rules": [
{
"user": ["roam@example.com"],
"outboundTag": "reverse-out"
}
]
},
"outbounds": [
{
"protocol": "freedom"
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Конфигурация Домашнего Устройства
Домашнее устройство по-прежнему должно само подключаться к публичному серверу и поднимать обратный туннель. В отличие от первой части, теперь оно не переписывает весь трафик на один фиксированный Web-сервис, а передает весь трафик, пришедший через reverse-in, на домашний outbound прямого подключения для дальнейшей обработки.
В примере ниже предполагается:
- Домашняя подсеть имеет вид
192.168.1.0/24; - Пользовательское устройство уже само решает, какой трафик нужно "вернуть домой";
- Домашнее устройство только принимает этот трафик и передает его домашней сети для дальнейшей обработки.
{
"routing": {
"rules": [
{
"inboundTag": ["reverse-in"],
"outboundTag": "home-direct"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "home-direct",
"settings": {
"finalRules": [
{
"action": "allow",
"network": "tcp,udp",
"ip": ["192.168.1.0/24"]
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-in"
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Смысл этих правил:
- Любой трафик, входящий через
reverse-in, отправляется вhome-direct; - Поскольку в Xray есть политика безопасности по умолчанию, через
finalRulesнужно явно разрешить доступ во внутреннюю домашнюю сеть. Если вам нужен доступ только к домашнему NAS, лучше не открывать все IP, как в примере, а разрешить только конкретные IP и порты по необходимости.
Конфигурация Устройства Пользователя
На стороне пользовательского устройства обычно не рекомендуется по умолчанию "возвращать домой весь трафик". Более распространенный вариант - отправлять назад только тот трафик, которому нужен доступ к домашним ресурсам, а остальной трафик оставлять на локальном прямом подключении. Ниже приведен пример, соответствующий домашней конфигурации выше. Предположим:
- Пользователь хочет обращаться только к домашней подсети
192.168.1.0/24; - Остальной трафик продолжает идти напрямую из локальной сети пользователя.
{
"routing": {
"rules": [
{
"ip": ["192.168.1.0/24"],
"outboundTag": "roam-home"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "vless",
"tag": "roam-home",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision"
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Смысл этих правил:
- Трафик, направленный в
192.168.1.0/24, идет черезroam-home; - Остальной трафик не попадает ни под одно правило и продолжает идти через
freedomпо умолчанию, то есть напрямую через локальную сеть.
С точки зрения пользователя это выглядит как "домой отправляется только та часть трафика, которая нужна для доступа к домашним ресурсам", а не как перенаправление всего интернет-трафика через публичный сервер с последующим возвратом домой.
Поток Запроса
Чем Этот Вариант Отличается От Первого
- Первый вариант - это "сопоставить один публичный входной порт с фиксированным сервисом в удаленной внутренней сети"; без дополнительной аутентификации такой сервис может быть доступен любому пользователю из интернета.
- Эта часть - это "дать конкретному пользователю сначала подключиться к публичному Xray-серверу, а затем через обратный прокси вернуться домой и продолжить доступ";
- Первый вариант больше похож на удаленный проброс порта, то есть на проникновение во внутреннюю сеть;
- Эта часть больше похожа на удаленный роуминг или легкую межплощадочную сеть.
Рекомендации По Безопасности
- Если у вас несколько роуминговых пользователей, рекомендуется выдавать каждому отдельный UUID или отдельный идентификатор;
- В примере ради упрощения используется только VLESS-enc. В реальной эксплуатации могут понадобиться REALITY, XHTTP или другие способы маскировки трафика.
Расширение
Если вам нужен не режим "доступа к нескольким фиксированным внутренним ресурсам" в формате point-to-site, а межсайтовая L4-сеть, это можно сочетать с таблицами маршрутизации и TUN, либо использовать Xray как шлюз для прозрачного проксирования.
Выход Через Домашний Канал
Отправить выбранный трафик обратно на домашнее устройство, а затем продолжить выход во внешний интернет через домашний широкополосный канал.
Описание Сценария
Эта часть не про доступ к домашнему NAS, панели роутера или другим внутренним сервисам. Вместо этого пользователь сначала подключается к публичному Xray-серверу, затем по уже установленному обратному туннелю часть трафика отправляется обратно на домашнее устройство, а уже оттуда продолжается выход во внешний интернет через домашний широкополосный канал.
Этот вариант ближе к следующим сценариям:
- Когда нужно, чтобы выбранный трафик выходил с IP домашнего широкополосного подключения;
- Когда дома нет выделенного публичного IP, нет возможности сделать IPv4-проброс порта, открыть IPv6 firewall или просто не хочется выставлять порт наружу и возиться с DDNS;
- Когда публичный сервер сначала принимает пользователей, а затем отправляет обратно домой только тот трафик, которому нужен домашний выход.
TIP
Один из конкретных сценариев - использовать домашний широкополосный выход, чтобы ChatGPT не становился "глупее". В отличие от разблокировки стримингов, здесь нужен действительно выделенный резидентский выход. На практике поставщиком такого "настоящего домашнего канала" часто оказывается ваш друг, а перенастраивать его ONT или роутер крайне неудобно. Поэтому самый простой вариант - дать ему устройство, которому достаточно доступа в интернет, и запустить на нем Xray. VLESS reverse proxy очень хорошо ложится на такой сценарий.
Если смотреть шире, даже телефон вашего очень терпеливого друга может работать 7 x 24 как устройство выхода. Для сотовой сети эффект тот же. Здесь уже проверяется дружба.
Идея Конфигурации
Почти все то же самое, что и во второй части. Меняется только то, на что именно смотрит маршрутизация. Во второй части используется user -> reverse-out, а здесь - определенные домены -> reverse-out. Сам механизм обратного соединения между публичным сервером и домашним устройством не меняется.
Конфигурация Публичного Сервера
В этом примере:
- Первый UUID по-прежнему используется домашним устройством для установления обратного соединения;
- Второй UUID используется внешним пользователем для подключения к публичному серверу;
- Маршрутизация отправляет трафик к
geosite:openaiвreverse-out.
Сторона публичного сервера почти совпадает со второй частью. Разница только в том, что теперь маршрутизация идет по domain, а не по user.
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 8443,
"protocol": "vless",
// Здесь рекомендуется включить sniffing, иначе доменное правило может не увидеть целевой домен
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
},
"settings": {
"decryption": "mlkem768x25519plus.native.600s.aCF82eKiK6g0DIbv0_nsjbHC4RyKCc9NRjl-X9lyi0k",
"clients": [
{
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-out"
}
},
{
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision"
}
]
}
}
],
"routing": {
"rules": [
{
"domain": ["geosite:openai"],
"outboundTag": "reverse-out"
}
]
},
"outbounds": [
{
"protocol": "freedom"
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Смысл этих правил:
- Домашнее устройство возвращается на публичный сервер с первым UUID;
- Внешний пользователь подключается к публичному серверу со вторым UUID;
- Для этого публичного inbound рекомендуется включить
sniffing, иначе доменное правило может не увидеть целевой домен; - Любой запрос, попавший под
geosite:openai, отправляется вreverse-out; - Остальной трафик, не попавший под правило, идет через
freedomпо умолчанию, то есть остается на локальном выходе публичного сервера.
Конфигурация Домашнего Устройства
Домашняя сторона тоже почти совпадает со второй частью. На этот раз она больше не ограничивается одной внутренней подсетью, а разрешает все адреса, кроме приватных, чтобы трафик мог дальше выходить во внешний интернет через домашний канал.
{
"routing": {
"rules": [
{
"inboundTag": ["reverse-in"],
"outboundTag": "home-direct"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "home-direct",
"settings": {
"finalRules": [
{
"action": "allow",
"network": "tcp,udp",
"ip": ["!geoip:private"]
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-in"
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Смысл этих правил:
- Любой трафик, входящий из
reverse-in, передается вhome-direct; home-directчерезfinalRulesразрешает только трафик во внешний интернет.
Конфигурация Устройства Пользователя
На стороне пользователя достаточно классической схемы "cn -> direct, все остальное через прокси":
{
"routing": {
"rules": [
{
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"ip": ["geoip:private", "geoip:cn"],
"outboundTag": "direct"
}
]
},
"outbounds": [
{
"protocol": "vless",
"tag": "to-server",
"settings": {
"address": "yourserver.com",
"port": 8443,
"encryption": "mlkem768x25519plus.native.0rtt.2PcBa3Yz0zBdt4p8-PkJMzx9hIj2Ve-UmrnmZRPnpRk",
"id": "e8758aff-d830-4d08-a59e-271df65b995a",
"flow": "xtls-rprx-vision"
}
},
{
"protocol": "freedom",
"tag": "direct"
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Смысл этих правил:
- Доменные имена и IP внутри Китая продолжают идти напрямую из локальной сети;
- Остальной трафик, не попавший под правила, по умолчанию идет через
to-server, то есть отправляется на публичный сервер; - Уже на публичном сервере правило
geosite:openai -> reverse-outиз предыдущего раздела решает, какой трафик нужно пустить через домашний канал.
Поток Запроса
Чем Этот Вариант Отличается От Второй Части
- Во второй части цель - "вернуться домой и получить доступ к внутренним ресурсам";
- В этой части цель - "вернуться домой и воспользоваться домашним каналом для выхода во внешний интернет";
- Во второй части основная логика маршрутизации - "каких пользователей нужно вернуть домой";
- В этой части основная логика маршрутизации - "какие домены должны идти через домашний канал".
Итоги
К этому моменту статья охватывает три основных сценария и одну производную возможность для обратного прокси VLESS:
- Удаленный проброс порта: сопоставление публичного входного порта с конкретным сервисом в удаленной внутренней сети;
- Point-to-site VPN: подключение пользователя к публичному серверу с последующим возвратом домой через обратный туннель;
- Site-to-site VPN: использование того же механизма как строительного блока для L4-сети между площадками;
- Выход через домашний канал: возврат выбранного трафика домой через публичный сервер с последующим выходом во внешний интернет через домашний широкополосный канал.
Во всех случаях используется один и тот же механизм обратного соединения. Основное различие состоит в том, как публичная сторона маршрутизирует трафик и как внутренняя сторона продолжает его обрабатывать. Эта статья только перечисляет несколько типовых схем; гораздо важнее понять сам механизм. Когда принцип станет понятен, его можно дальше расширять под свои задачи.
Продвинутые Приемы: Расширенная Балансировка Нагрузки
Если у вас есть несколько входов, несколько выходов или обратные соединения из разных регионов, и вы хотите, чтобы группа линий обратного прокси автоматически переживала отказы и распределяла трафик, можно заставить несколько соединений использовать один и тот же reverse.tag, то есть объединить их в единый пул доступности.
Если на публичной стороне несколько входящих подключений используют один и тот же reverse tag, в итоге все равно будет создан только один outbound. Это можно понимать как несколько линий, подвешенных к одному общему пулу доступности, где при каждом использовании случайно выбирается одна из живых линий.
Если какая-то линия временно недоступна, например потому что соответствующее внутреннее устройство еще не подключилось, она просто не попадет в текущий пул доступности. Последующий трафик будет автоматически перенаправляться на другие линии, которые все еще в сети, без ручного переключения.
Та же логика именования разрешена и на внутренней стороне: несколько VLESS outbound тоже могут использовать один и тот же reverse-in.
Иначе говоря, reverse.tag допускает одинаковые имена на обеих сторонах, и одинаковые теги будут объединяться:
- Несколько клиентов на публичной стороне, использующих один и тот же
reverse-out, сходятся в один пул outbound; - Несколько VLESS outbound на внутренней стороне, использующих один и тот же
reverse-in, сходятся в один пул inbound.
Поэтому схема естественно масштабируется до N-к-N. Более типичный реальный сценарий выглядит так: снаружи есть только один сервисный домен, например www.example.com, а GeoDNS отправляет посетителей на ближайший публичный сервер в Лос-Анджелесе или Токио. На внутренней стороне при этом устанавливаются соединения назад к us-reverse.example.com и jp-reverse.example.com. Затем разворачиваются два внутренних устройства: дома и в офисе, и оба подключаются и к Лос-Анджелесу, и к Токио. Каждый публичный узел тогда поддерживает пул доступности вида "дом + офис". При реальной переадресации случайно выбирается одна доступная линия из уже установленных соединений. Если одна из точек уходит офлайн, она автоматически исчезает из пула.
Ниже приведен минимальный фрагмент, в котором оставлены только части, связанные с reverse, и по-прежнему используется модель "публичный входной порт отображается на внутренний сервис".
Публичный Сервер В Лос-Анджелесе
{
"inbounds": [
{
"port": 8443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "us-home-uuid",
"reverse": {
"tag": "reverse-out"
}
},
{
"id": "us-office-uuid",
"reverse": {
"tag": "reverse-out"
}
}
]
}
},
{
"port": 443,
"protocol": "tunnel",
"tag": "portal"
}
],
"routing": {
"rules": [
{
"inboundTag": ["portal"],
"outboundTag": "reverse-out"
}
]
},
"outbounds": [
{
"protocol": "freedom"
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Публичный Сервер В Токио
Полностью та же идея, только UUID меняются на jp-home-uuid и jp-office-uuid.
Домашнее Внутреннее Устройство
{
"routing": {
"rules": [
{
"inboundTag": ["reverse-in"],
"outboundTag": "reverse-direct"
}
]
},
"outbounds": [
{
"protocol": "freedom",
"tag": "reverse-direct",
"settings": {
"redirect": "192.168.1.123:80",
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.123",
"port": "80"
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "us-reverse.example.com",
"port": 8443,
"id": "us-home-uuid",
"reverse": {
"tag": "reverse-in"
}
}
},
{
"protocol": "vless",
"settings": {
"address": "jp-reverse.example.com",
"port": 8443,
"id": "jp-home-uuid",
"reverse": {
"tag": "reverse-in"
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Офисное Внутреннее Устройство
Полностью аналогично домашнему внутреннему устройству, только UUID меняются на us-office-uuid и jp-office-uuid, а redirect нужно заменить на тот внутренний сервис, который должен публиковаться из офиса.
Расширение
Если вы хотите, чтобы выбор здесь был не просто "случайно взять одну из доступных линий", а зависел от задержки, стабильности или результатов наблюдений, это можно дополнительно сочетать с routing.balancer и спроектировать более тонкую политику выбора outbound.
Продвинутые Приемы: Передача Реального IP Посетителя
Если вы хотите, чтобы внутренний Web-сервис видел реальный IP посетителя, а не определял источник как IP машины с Xray на внутренней стороне, можно включить proxyProtocol у outbound freedom на внутренней стороне. Если он выключен, backend Web-сервер обычно видит адрес самой внутренней машины с Xray. Если он включен, Xray перед пересылкой соединения на backend, указанный в redirect, сначала отправляет заголовок PROXY protocol, чтобы вместе с ним передать Web-серверу и реальный исходный адрес.
Например:
{
"outbounds": [
{
"protocol": "freedom",
"tag": "reverse-direct",
"settings": {
"redirect": "192.168.1.123:80",
"proxyProtocol": 1,
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.123",
"port": "80"
}
]
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
В этом случае backend, на который указывает redirect, не может быть просто обычным HTTP listener. На нем также нужно явно включить поддержку PROXY protocol. Предположим, что Web-сервер расположен по адресу 192.168.1.123, а адрес внутреннего Xray — 192.168.1.10. Для nginx, например, конфигурация может выглядеть так:
server {
listen 80 proxy_protocol;
server_name _;
set_real_ip_from 192.168.1.10;
real_ip_header proxy_protocol;
location / {
root /srv/www/html;
index index.html;
}
}2
3
4
5
6
7
8
9
10
11
12
Строка set_real_ip_from 192.168.1.10; выше означает, что доверять нужно только PROXY protocol header, пришедшему от внутреннего Xray. 192.168.1.10 здесь приведен лишь как пример; замените его на реальный IP вашей внутренней машины с Xray. proxyProtocol может быть равен 1 или 2. Если backend это поддерживает, конфигурация на стороне nginx остается той же.
Продвинутые Приемы: Точная Маршрутизация По Домену И IP Посетителя На Внутренней Стороне
Если вы хотите, чтобы извне были доступны сразу несколько внутренних сайтов, и эти сайты находятся не на одной машине, можно включить sniffing прямо на входе обратного прокси, извлечь доменное имя из HTTP Host или TLS SNI, а затем по домену отправлять трафик в разные outbound freedom. Так публичная сторона сохранит только одну точку входа, а внутренняя сторона все равно сможет разводить трафик по разным хостам в зависимости от сайта.
При этом обратный прокси VLESS сохраняет реальный source IP посетителя. Когда трафик попадает во внутреннюю систему маршрутизации, можно продолжить использовать sourceIP для более точного контроля, например отправлять некоторые источники сразу в blackhole или направлять определенные источники в другую группу backend-серверов. Ниже приведен комбинированный пример:
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"inboundTag": ["reverse-in"],
"sourceIP": ["!geoip:cn"],
"outboundTag": "reverse-block"
},
{
"inboundTag": ["reverse-in"],
"domain": ["full:admin.example.com"],
"outboundTag": "reverse-admin"
},
{
"inboundTag": ["reverse-in"],
"domain": ["domain:blog.example.com"],
"outboundTag": "reverse-blog"
},
{
"inboundTag": ["reverse-in"],
"outboundTag": "reverse-default"
}
]
},
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "blackhole",
"tag": "reverse-block"
},
{
"protocol": "freedom",
"tag": "reverse-admin",
"settings": {
"redirect": "192.168.1.10:8443",
"proxyProtocol": 1,
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.10",
"port": "8443"
}
]
}
},
{
"protocol": "freedom",
"tag": "reverse-blog",
"settings": {
"redirect": "192.168.1.20:8080",
"proxyProtocol": 1,
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.20",
"port": "8080"
}
]
}
},
{
"protocol": "freedom",
"tag": "reverse-default",
"settings": {
"redirect": "192.168.1.30:80",
"proxyProtocol": 1,
"finalRules": [
{
"action": "allow",
"network": "tcp",
"ip": "192.168.1.30",
"port": "80"
}
]
}
},
{
"protocol": "vless",
"settings": {
"address": "yourserver.com",
"port": 8443,
"id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
"flow": "xtls-rprx-vision",
"reverse": {
"tag": "reverse-in",
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
}
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Ключевые моменты этого примера:
reverse.sniffingвключается внутриreverseу внутреннего VLESS outbound, то есть sniffing выполняется для соединений, пришедших через вход обратного прокси;- Правила маршрутизации проверяются по порядку, поэтому ограничительные правила вроде
sourceIP -> blackholeнужно ставить раньше; proxyProtocolнужен только для того, чтобы передавать реальный IP посетителя дальше в backend-приложение. Если вам нужна только маршрутизация внутри Xray поsourceIP, его можно не включать.
С такой конфигурацией одна публичная точка входа может обслуживать сразу несколько внутренних сайтов, а внутренняя сторона при этом сохраняет возможность более гибко отбрасывать, маршрутизировать и аудировать трафик по адресу источника посетителя.
Замечания По Безопасности
Следующие пункты больше относятся к безопасному развертыванию и контролю границ. Рекомендуется внимательно прочитать их перед использованием этой схемы в продакшене:
- UUID, используемый для обратного проксирования, нельзя разделять с обычными клиентами прямого прокси. Его нужно создавать отдельно. Кроме того, UUID для обратного прокси нужно бережно хранить: если конфигурация клиента утечет, злоумышленник может попытаться перехватить ваш reverse tunnel.
- Для соединения, используемого в сценарии внутреннего проникновения, даже при включенном
XTLS Visionпрактический выигрыш сейчас в основном ограничивается такими вещами, какpadding. Это не то же самое, что часто обсуждаемый эффект "прямого оголенного канала". Нужно ли также включать XTLS на соединении, обращенном к конечным пользователям, зависит от вашей реальной топологии и модели угроз. - Внутренний outbound
freedom, который принимает трафик обратного прокси, то есть привычныйdirect, желательно настраивать по принципу минимально необходимых привилегий. Сделайте outbound по умолчанию равнымblackhole, явно маршрутизируйте только разрешенные цели в выделенныйfreedom, а затем черезfinalRulesоткрывайте только действительно нужные адреса и порты. - Если вы используете сервис проникновения, предоставленный кем-то другим, для удаленного доступа домой, или если вы не полностью доверяете публичному VPS, лучше не направлять трафик обратного прокси напрямую на реальные внутренние сервисы. Вместо этого можно развернуть на внутренней стороне еще один сервер с включенным
VLESS Encryption, специально для приема такого трафика, и уже через него пересылать трафик к настоящему сервису. Это добавляет аутентификацию и защиту данных; иначе любой, кто имеет достаточный доступ к публичному серверу, потенциально сможет перемещаться по вашей внутренней сети. - Когда трафик доставляется на внутреннюю сторону через входящие протоколы вроде
VLESS, протокол, который routing system показывает уSourceилиLocal, не обязательно совпадает с итоговымTarget. При использовании условий вродеsource,localилиnetworkориентируйтесь на реальную форму трафика, а не на предположение, что они эквивалентны. - Три HTTP-ориентированных inbound
XHTTP,WebSocketиHTTPUpgradeпо умолчанию доверяютX-Forwarded-For. Если перед ними нет доверенного HTTP reverse proxy, рекомендуется сочетать это сsockopt.trustedXForwardedFor, чтобы ограничить случаи доверия и не допустить подделки исходного IP клиентом.